﻿using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

namespace MyDemo.Reflection
{
    public class ReflectDemo
    {
        //调用带参实例方法fun
        public static void Test()
        {
            Type T1 = typeof(TClass);
            T1.InvokeMember("fun", BindingFlags.InvokeMethod, null, new TClass(), new string[] { "test" });
        }

        //调用无参实例方法fun2
        public static void Test2()
        {
            Type T1 = typeof(TClass);
            T1.InvokeMember("fun2", BindingFlags.InvokeMethod, null, new TClass(), null);
        }

        // 调用静态方法
        public static void Test3()
        {
            Type T1 = typeof(TClass);
            T1.InvokeMember("fun3", BindingFlags.InvokeMethod, null, T1, null);
        }

        /// <summary>
        /// http://blog.zhaojie.me/2008/11/invoke-method-by-lambda-expression.html
        /// </summary>
        public static void Test4()
        {
            int times = 1000;

            ReflectDemo instance = new ReflectDemo();
            object[] parameters = new object[] { new object(), new object(), new object() };
            instance.Call(null, null, null);

            //=====================Directly invoke====================
            Stopwatch watch1 = new Stopwatch();
            watch1.Start();
            for (int i = 0; i < times; i++)
            {
                instance.Call(parameters[0], parameters[1], parameters[2]);
            }
            watch1.Stop();
            Console.WriteLine(watch1.Elapsed + "{Directly Invoke}");

            //=====================Reflection invoke=================
            MethodInfo methodInfo = typeof(ReflectDemo).GetMethod("Call");
            Stopwatch watch2 = new Stopwatch();
            watch2.Start();
            for (int i = 0; i < times; i++)
            {
                methodInfo.Invoke(instance, parameters);
            }
            watch2.Stop();
            Console.WriteLine(watch2.Elapsed + " (Reflection Invoke)");

            // =====================Expressioin invoke=================
            var dlg = GetVoidDelegate();
      
            Stopwatch watch3 = new Stopwatch();
            watch3.Start();
            for (int i = 0; i < times; i++)
            {
                dlg(instance, parameters);
            }
            watch3.Stop();
            Console.WriteLine(watch3.Elapsed + " (Expressioin Invoke)");
        }

        public void Call(object o1, object o2, object o3)
        {}

        public static Action<object, object[]> GetVoidDelegate()
        {
            Expression<Action<object, object[]>> exp = (instance, parameters) =>
                ((ReflectDemo)instance).Call(parameters[0], parameters[1], parameters[2]);

            Action<object, object[]> action = exp.Compile();

            return action;
        }
    }

    public class TClass
    {
        public void fun(string str)
        {
            Console.WriteLine("我是fun方法，我被调用了。" + str);
        }

        public void fun2()
        {
            Console.WriteLine("我是fun2方法，我被调用了。");
        }

        public static void fun3()
        {
            Console.WriteLine("我是fun3静态方法,我被调用了");
        }
    }
}